﻿using GeneralTheGame;
using System.IO;
using System;
using TeamWork.Dig;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Linq;

class TheGame
{
    private static int[] sixes = new int[5] { 6, 6, 6, 6, 6 };
    private const int readRules = 22;
    private const int startGame = 24;
    private const int highScores = 26;
    private const int exit = 28;
    private static Player[] players;
    public static string maxScore = "MaxScore.txt";

    private static void ChoiceModeMenu()
    {
        int choice = 22;
        Draw(40, choice, ConsoleColor.DarkRed, "-->");
        while (true)
        {

            if (Console.KeyAvailable)
            {
                Draw(40, choice, ConsoleColor.Black, "-->");

                ConsoleKeyInfo userChoice = Console.ReadKey();
                if (userChoice.Key == ConsoleKey.DownArrow)
                {
                    choice += 2;
                }
                if (userChoice.Key == ConsoleKey.UpArrow)
                {
                    choice -= 2;
                }
                if (userChoice.Key == ConsoleKey.Enter)
                {
                    break;
                }

                if (choice > 28)
                {
                    choice = 22;
                }
                if (choice < 22)
                {
                    choice = 28;
                }

                Draw(40, choice, ConsoleColor.DarkRed, "-->");
            }
            Thread.Sleep(100);
        }

        Console.Clear();

        if (choice == readRules)
        {
            PrintRules();
        }
        else if (choice == startGame)
        {
            StartGame();
        }
        if (choice == highScores)
        {
            PrintHighScore();
        }
        if (choice == exit)
        {
            return;
        }
    }

    static void PlayersLogIn(int top)
    {
        Console.SetCursorPosition(30, top);
        Console.ForegroundColor = ConsoleColor.Red;
    }

    private static void Draw(int posX, int posY, ConsoleColor color, string str)
    {
        Console.SetCursorPosition(posX, posY);
        Console.ForegroundColor = color;
        Console.Write(str);
        Console.ForegroundColor = ConsoleColor.White;
    }
  
    static void EndGame()
    {
        Console.Clear();
        int maxScore = players.Max(p => p.TotalPlayerScore);
        Player player = players.Where(p => p.TotalPlayerScore == maxScore).First();
        Draw(30, 20, ConsoleColor.Green, string.Format("The Winner is {0} with score: {1}", player.PlayerName, player.TotalPlayerScore));
        Console.WriteLine();
        ResultTable.SavePlayersMaxScore(player.PlayerName, player.TotalPlayerScore);

        Draw(49, 29, ConsoleColor.DarkCyan, "Press any key to get back");

        bool isPressedKey = false;
        while (!isPressedKey)
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo keyPressed = Console.ReadKey();
                if (keyPressed.Key == keyPressed.Key)
                {
                    Console.Clear();
                    isPressedKey = true;
                }
            }
        }

        StartScreen();
        ChoiceModeMenu();
    }

    // Rules
    private static void PrintRules()
    {
        Console.BufferHeight = Console.WindowHeight = 49;
        Console.BufferWidth = Console.WindowWidth = 125;
        Console.ForegroundColor = ConsoleColor.White;

        try
        {
            StreamReader rules = new StreamReader("Rules.txt", Encoding.UTF8);

            using (rules)
            {
                Console.WriteLine(rules.ReadToEnd());
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("File \"Rules.txt\" not found.");
        }

        bool isPressedKey = false;
        while (!isPressedKey)
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo keyPressed = Console.ReadKey();
                if (keyPressed.Key == keyPressed.Key)
                {
                    Console.Clear();
                    isPressedKey = true;
                }
            }
        }

        StartScreen();
        ChoiceModeMenu();
    }

    static void PrintHighScore()
    {
        // max players to show
        int maxPlayers = 5;
        Draw(30, 13, ConsoleColor.DarkCyan, string.Format("TOP {0} HIGH SCORE PLAYERS", maxPlayers));
        Draw(30, 14, ConsoleColor.DarkCyan, "#   Player     Points");

        try 
	    {
            using (StreamReader reader = new StreamReader(maxScore))
            {
                int startIndex = 1;
                while (!reader.EndOfStream)
                {
                    string[] line = reader.ReadLine().Split(' ');
                    Draw(30, 14 + startIndex, ConsoleColor.Green, string.Format("{0,-3} {1,-10} {2,-6}", line[0].Replace(".", string.Empty), line[1], line[2]));
                    if (startIndex == maxPlayers)
                    {
                        break;
                    }
                    startIndex++;
                }
            }
            Draw(49, 29, ConsoleColor.DarkCyan, "Press any key to get back");
	    }
        catch (FileNotFoundException)
        {
            Console.WriteLine("File not found.");
        }

        bool isPressedKey = false;
        while (!isPressedKey)
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo keyPressed = Console.ReadKey();
                if (keyPressed.Key == keyPressed.Key)
                {
                    Console.Clear();                 
                    isPressedKey = true;
                }
            }
        }

        StartScreen();
        ChoiceModeMenu();
    }

    #region SignOnStartScreen
    static void SortWordMatrix(string a, string[,] matrix, ref int j)
    {
        int count = -1;
        for (int row = 0; row < 7; row++)
        {
            for (int col = 0; col == col % 10; col++)
            {
                matrix[row, j + col] = a[++count].ToString();
            }
        }

        j += 10;
    }

    private static void PrintFirstPageWords()
    {
        Console.SetCursorPosition(15, 5);
        int j = 0;
        string g = "********  " + "*         " + "*         " + "*     **  " + "*      *  " + "*      *  " + "********  ";
        string e = "********  " + "*         " + "*         " + "********  " + "*         " + "*         " + "********  ";
        string n = "**     *  " + "* *    *  " + "*  *   *  " + "*   *  *  " + "*    * *  " + "*     **  " + "*      *  ";
        string r = "*******   " + "*      *  " + "*      *  " + "*******   " + "* *       " + "*  *      " + "*   ****  ";
        string a = "  ****** *" + " *      **" + "*        *" + "*        *" + "*        *" + " *      **" + "  ****** *";
        string l = "  *       " + "  *       " + "  *       " + "  *       " + "  *      *" + "  *      *" + "  ********";

        string[,] matrix = new string[7, 70];

        SortWordMatrix(g, matrix, ref j);
        SortWordMatrix(e, matrix, ref j);
        SortWordMatrix(n, matrix, ref j);
        SortWordMatrix(e, matrix, ref j);
        SortWordMatrix(r, matrix, ref j);
        SortWordMatrix(a, matrix, ref j);
        SortWordMatrix(l, matrix, ref j);

        for (int row = 0; row < 7; row++)
        {
            Console.SetCursorPosition(15, 5 + row);
            for (int col = 0; col < 70; col++)
            {
                if (matrix[row, col] == "*")
                {
                    Console.ForegroundColor = ConsoleColor.DarkRed;
                    string myString = "\u2588";
                    Console.Write(myString);
                    Console.ResetColor();
                }
                else
                {
                    Console.Write(matrix[row, col]);
                }
            }
            Console.WriteLine();
        }
    }
    #endregion

    private static void StartScreen()
    {
        Console.BufferHeight = Console.WindowHeight = 40;
        Console.BufferWidth = Console.WindowWidth = 100;

        Print.RowPrint(sixes, 25, 15);

        PrintFirstPageWords();
        Draw(75, 30, ConsoleColor.White, "\"Johnny Cage Team\"");
        Draw(45, 22, ConsoleColor.DarkRed, "Read rules");
        Draw(45, 24, ConsoleColor.DarkRed, "Start game!");
        Draw(45, 26, ConsoleColor.DarkRed, "High scores");
        Draw(45, 28, ConsoleColor.DarkRed, "Exit game");

    }

    static string DetermineCombinationName(int index)
    {
        string combinationName = string.Empty;
        switch (index)
        {
            case 0:
                combinationName = "Ones";
                break;
            case 1:
                combinationName = "Twos";
                break;
            case 2:
                combinationName = "Threes";
                break;
            case 3:
                combinationName = "Fours";
                break;
            case 4:
                combinationName = "Fives";
                break;
            case 5:
                combinationName = "Sixes";
                break;
            case 6:
                combinationName = "One pair";
                break;
            case 7:
                combinationName = "Two pairs";
                break;
            case 8:
                combinationName = "Three of a kind";
                break;
            case 9:
                combinationName = "Four of a kind";
                break;
            case 10:
                combinationName = "Full House";
                break;
            case 11:
                combinationName = "Small Straight";
                break;
            case 12:
                combinationName = "Large Straight";
                break;
            case 13:
                combinationName = "Chance";
                break;
            case 14:
                combinationName = "Generale";
                break;
            default:
                break;
        }

        return combinationName;
    }

    static int PrintAvailableCombinations(int xPos, int yPos, List<int> scoreList, Player currentPlayer)
    {
        Console.SetCursorPosition(xPos, yPos);
        Console.WriteLine("Available combinations: ");
        yPos++;
        for (int i = 0; i < scoreList.Count; i++)
        {
            Console.SetCursorPosition(xPos, yPos++);
            int playerCombinationIndex = i;
            if (i > 5)
            {
                playerCombinationIndex++;
            }

            if (currentPlayer.PlayerCombinations[playerCombinationIndex] == true)
            {
                continue;
            }

            string combinationName = DetermineCombinationName(i);

            bool isChangedCollor = false;
            if (i % 2 == 0)
            {
                Console.ForegroundColor = ConsoleColor.DarkCyan;
                isChangedCollor = true;
            }
            Console.WriteLine("{0} - {1}: {2} points", i + 1, combinationName, scoreList[i]);
            if (isChangedCollor)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
                isChangedCollor = false;
            }
        }

        return yPos;
    }

    static List<string> combinationList = new List<string>()
    {
        "1", // ones
        "2", // twos
        "3", // threes
        "4", // fours
        "5", // fives
        "6", // sixes
        "7", // one pair
        "8", // two pairs
        "9", // three of a kind
        "10", // four of a kind
        "11", // full house
        "12", // small straight
        "13", // large straight
        "14", // chance
        "15" // generale
    };


    // Command parser, the main function which determines what function to call and when
    // Returns byte which work instead of boolean values
    // -1 means end command is passed and the program should stop execution
    // 0 means that there is an unrecognized command passed in or an error in execution and the player should repeat
    // 1 means that execution finished successfully
    static int ParseCommand(string command, Player currentPlayer, string[,] resultTable, int playerCount, int currentPlayerNumber, List<int> scoreList = null)
    {
        string[] split = command.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

        try
        {
            switch (split[0])
            {
                case "roll":
                    if (split.Length == 1)
                    {
                        currentPlayer.RollAllDice();

                        int[] getThrows = new int[5];
                        for (int i = 0; i < getThrows.Length; i++)
                        {
                            getThrows[i] = currentPlayer.PlayerDice[i].GetLastThrow();
                        }
                        Console.Clear();
                        ResultTable.PrintTable(resultTable, playerCount, currentPlayerNumber);
                        Print.RowPrint(getThrows);

                        return 1;
                    }
                    else
                    {

                        var diceToRoll = new List<int>();

                        for (int i = 1; i < split.Length; i++)
                        {
                            int valueToAdd = int.Parse(split[i]);
                            if (valueToAdd > 5 || valueToAdd < 0)
                            {
                                return 0;
                            }

                            diceToRoll.Add(int.Parse(split[i]));
                        }

                        currentPlayer.ThrowDice(diceToRoll);

                        try
                        {
                            int[] getThrows = new int[5];
                            for (int i = 0; i < getThrows.Length; i++)
                            {
                                getThrows[i] = currentPlayer.PlayerDice[i].GetLastThrow();
                            }

                            Console.Clear();
                            ResultTable.PrintTable(resultTable, playerCount, currentPlayerNumber);
                            Print.RowPrint(getThrows);
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                            Console.WriteLine("You have to throw all dice first!");
                            return 0;
                        }

                        return 1;
                    }
                case "end":
                    //EndGame();
                    return -1;
                default:
                    if (!combinationList.Contains(command))
                    {
                        return 0;
                    }
                    else
                    {
                        int indexToAdd = combinationList.IndexOf(command);
                        bool flag = currentPlayer.SetPlayerCombination(indexToAdd, scoreList[indexToAdd]);

                        Console.Clear();
                        ResultTable.PrintTable(resultTable, playerCount, currentPlayerNumber);

                        if (flag == false)
                        {
                            return 0;
                        }
                        return 2;
                    }
            }
        }
        catch (IndexOutOfRangeException)
        {
            Console.WriteLine("You must enter a valid command!");
            return 0;
        }
    }

    private static void GameBody(string[,] resultTable, Player[] players)
    {
        for (int k = 0; k < 15; k++)
        {
            for (int i = 0; i < players.Length; i++)
            {
                var lastScoreList = new List<int>();
                bool breakflag = false;
                for (int j = 0; j < 4; j++)
                {
                    if (breakflag)
                    {
                        break;
                    }
                     
                    Console.SetCursorPosition(25, 26);
                    Console.WriteLine("{0}'s turn!", players[i].PlayerName);
                    
                    string command = string.Empty;
                    int result = 0;

                    var scoreList = new List<int>();
                    if (j == 0)
                    {
                        resultTable = ResultTable.GetPlayerResults(resultTable, players);
                        result = ParseCommand("roll", players[i], resultTable, players.Length, i + 1, null);
                        scoreList = CombinationDetection.DetectCombinations(players[i].PlayerDice);

                        for (int l = 9; l < 13; l++)
                        {
                            if (scoreList[l] > 0)
                            {
                                scoreList[l] *= 2;
                            }
                        }


                        PrintAvailableCombinations(20, 10, scoreList, players[i]);
                    }
                    else
                    {
                        Console.SetCursorPosition(0, 28);
                        if (j == 0 || j == 1 || j == 2 && result != 0)
                        {
                            Console.WriteLine("Write the number of combination, to save it in score table.\n" +
                            "Write \"roll\" and number of dice which you want to roll again,\nseparated with whitespace(roll 1 3 5)." +
                            "\nWrite \"roll\" to roll all dice again.\n" +
                            "Write \"end\" if you wish to end the game.");
                        }
                        else
                        {
                            Console.WriteLine("Write the number of result, to save it in score table.");
                        }
                        Console.Write("Make your choice: ");
                        command = Console.ReadLine().ToLower();
                    }

                    if (j == 3 && command.Contains("roll"))
                    {
                        PrintAvailableCombinations(20, 10, scoreList, players[i]);
                        while (command.Contains("roll"))
                        {
                            command = Console.ReadLine().ToLower();
                        }
                    }

                    if (command.Contains("roll") || command.Contains("end") && j != 0)
                    {
                        resultTable = ResultTable.GetPlayerResults(resultTable, players);
                        result = ParseCommand(command, players[i], resultTable, players.Length, i + 1, null);
                        scoreList = CombinationDetection.DetectCombinations(players[i].PlayerDice);

                        PrintAvailableCombinations(20, 10, scoreList, players[i]);
                    }
                    else if (j != 0)
                    {
                        resultTable = ResultTable.GetPlayerResults(resultTable, players);
                        scoreList = CombinationDetection.DetectCombinations(players[i].PlayerDice);
                        if (j == 1)
                        {
                            for (int n = 9; n < 13; n++)
                            {
                                    scoreList[n] *= 2;
                                }
                            }
                        result = ParseCommand(command, players[i], resultTable, players.Length, i + 1, scoreList);

                    }

                    if (result == -1)
                    {
                        return;
                    }
                    else if (result == 2)
                    {
                        break;
                    }

                    else if (result == 0)
                    {
                        while (result == 0)
                        {
                            Console.Clear();

                            int[] diceToPrint = new int[5];
                            for (int n = 0; n < 5; n++)
                            {
                                diceToPrint[n] = players[i].PlayerDice[n].GetLastThrow();
                            }

                            Print.PrintDig(diceToPrint, 10, 4);
                            PrintAvailableCombinations(20, 10, scoreList, players[i]);
                            resultTable = ResultTable.GetPlayerResults(resultTable, players);
                            ResultTable.PrintTable(resultTable, players.Length, i + 1);

                            Console.SetCursorPosition(20, 27);
                            Console.WriteLine("Unavailable combination or command!");
                            Console.SetCursorPosition(20, 28);
                            Console.WriteLine("Please try again");
                            Console.SetCursorPosition(25, 29);
                            command = Console.ReadLine();
                            if (j == 3 && command.Contains("roll"))
                            {
                                result = 0;
                            }
                            else
                            {
                                resultTable = ResultTable.GetPlayerResults(resultTable, players);
                                result = ParseCommand(command, players[i], resultTable, players.Length, i + 1, scoreList);
                                PrintAvailableCombinations(20, 10, scoreList, players[i]);
                                if (result == 2)
                                {
                                    breakflag = true;
                                }
                            }
                        }
                    }
                    lastScoreList = scoreList;
                }
            }
        }
    }

    private static void StartGame() 
    {
        // Players set and login
        Console.SetWindowSize(100, 40);
        Console.SetBufferSize(100, 40);


        int countOfPlayers = 0;
        bool isNOtCorrect = true;
        while (isNOtCorrect)
        {
            PlayersLogIn(5);
            Console.Write("Enter the count of players(max = 9): ");
            countOfPlayers = int.Parse(Console.ReadLine());
            if (countOfPlayers < 10)
            {
                isNOtCorrect = false;
            }
            Console.Clear();
        }
        

        Console.BufferHeight = 40;
        Console.WindowHeight = 40;
        Console.BufferWidth = 90 + 10 * countOfPlayers;
        Console.WindowWidth = 90 + 10 * countOfPlayers;

        players = new Player[countOfPlayers];
        for (int player = 0, newLineSpacer = 0; player < countOfPlayers; player++, newLineSpacer++)
        {
            PlayersLogIn(8 + player + newLineSpacer);
            Console.Write("Enter the name of Player {0}: ", player + 1);
            players[player] = new Player(Console.ReadLine(), ConsoleColor.Green);
        }
        Console.Clear();


        players[0].IsCurrentPlayer = true;
        string[,] result = ResultTable.CreateNewTable(countOfPlayers);
        result = ResultTable.GetPlayerResults(result, players);
        ResultTable.PrintTable(result, countOfPlayers, 1, 65, 4);

        GameBody(result, players);
        EndGame();
        
    }

    static void Main()
    {

        // Start screen
        StartScreen();

        // Menu
        ChoiceModeMenu();
    }
}
